package com.grace.service;

import com.google.common.collect.Lists;
import com.grace.beans.CacheKeyConstants;
import com.grace.common.RequestHolder;
import com.grace.dao.SysAclMapper;
import com.grace.dao.SysRoleAclMapper;
import com.grace.dao.SysRoleUserMapper;
import com.grace.model.SysAcl;
import com.grace.model.SysUser;
import com.grace.util.JsonMapper;
import com.grace.util.StringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysCoreService {

    @Autowired
    private SysAclMapper sysAclMapper;

    @Autowired
    private SysRoleUserMapper sysRoleUserMapper;

    @Autowired
    private SysRoleAclMapper sysRoleAclMapper;

    @Autowired
    private SysCacheService sysCacheService;


    /**
     * 获得当前的用户的权限列表
     */
    public List<SysAcl> getCurrentUserList() {
        //获得当前用户的id
        int userId = RequestHolder.getCurrentUser().getId();
        //获得当前的用户的权限列表
        return getUserAclList(userId);
    }

    /**
     * 获得角色-权限列表
     */
    public List<SysAcl> getRoleAclList(int roleId) {
        //根据查出来的角色id列表查权限id列表
        //传一个值就相当于列表里面只包含一条数据
        List<Integer> aclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (CollectionUtils.isEmpty(aclIdList)) {
            return Lists.newArrayList();
        }
        //根据查出来的权限id列表查权限表信息表
        return sysAclMapper.getByAclIdList(aclIdList);
    }

    /**
     * 获得传入用户的所有权限列表
     */
    public List<SysAcl> getUserAclList(int userId) {
        if (isSuperAdmin()) {
            //查询角色所有信息
            return sysAclMapper.findAll();
        }
        //根据用户id查所拥有的角色id列表
        List<Integer> userRoleIdList = sysRoleUserMapper.getRoleIdListByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdList)) {
            return Lists.newArrayList();
        }
        //根据查出来的角色id列表查权限id列表
        List<Integer> userAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
        if (CollectionUtils.isEmpty(userAclIdList)) {
            return Lists.newArrayList();
        }
        //根据查出来的权限id列表查权限表信息表
        return sysAclMapper.getByAclIdList(userAclIdList);


    }

    /**
     * 是否为超级管理员
     */
    public boolean isSuperAdmin() {
        // 这里是我自己定义了一个假的超级管理员规则，实际中要根据项目进行修改
        // 可以是配置文件获取，可以指定某个用户，也可以指定某个角色
        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser.getEmail().contains("admin")) {
            return true;
        }
        return false;
    }

    /**
     * 判断url权限
     * true为有权限访问
     * false为无权限访问
     */
    public boolean hasUrlAcl(String url) {
        //判断是否是超级管理员
        if (isSuperAdmin()) {
            return true; //是超级权限管理员, 则有权限访问
        }
        //判断权限列表
        List<SysAcl> aclList = sysAclMapper.getByUrl(url);
        if (CollectionUtils.isEmpty(aclList)) {
            return true; //如果权限列表为空, 则有权限访问
        }
//        List<SysAcl> userAclList = getCurrentUserList();
        List<SysAcl> userAclList = getCurrentUserAclListFromCache();
        Set<Integer> userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet());
        //用于判断是否有权限点
        boolean hasValidAcl = false;
        for (SysAcl acl : aclList) {
            //判断一个用户是否具有某个权限点的访问权限
            if (acl == null || acl.getStatus() != 1) { //权限点无效
                continue;//某一个不校验, 其他的不校验
            }
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                return true;
            }
        }
        //当前没有可以校验的权限点的时候
        if (!hasValidAcl) {
            return true;
        }
        return false;
    }

    /**
     * 从缓冲中获取当前用户的权限信息
     */
    public List<SysAcl> getCurrentUserAclListFromCache() {
        int userId = RequestHolder.getCurrentUser().getId();
        String cacheValue = sysCacheService.getFromCache(CacheKeyConstants.USER_ACLS, String.valueOf(userId));
        if (StringUtils.isBlank(cacheValue)) {
            List<SysAcl> userAclList = getCurrentUserList();
            if (CollectionUtils.isNotEmpty(userAclList)) {
                sysCacheService.saveCache(JsonMapper.obj2String(userAclList), 600, CacheKeyConstants.USER_ACLS, String.valueOf(userId));
            }
            return userAclList;
        }
        return JsonMapper.string2Obj(cacheValue, new TypeReference<List<SysAcl>>() {
        });
    }
}
